package com.sunbeam.common.utils.encrypt;

import java.security.Key;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;


/**
 * 
 * @ClassName: DESCoder
 * @Description: DES Security Encoding Components
 * @author lyz lyzpoq_gmail_com
 * @date 2013/09/17 16:20:57
 * 
 * <pre>
 * Support DES、DESede(TripleDES,as is 3DES)、AES、Blowfish、RC2、RC4(ARCFOUR)
 * DES          		key size must be equal to 56
 * DESede(TripleDES) 	key size must be equal to 112 or 168
 * AES          		key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
 * Blowfish     		key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
 * RC2          		key size must be between 40 and 1024 bits
 * RC4(ARCFOUR) 		key size must be between 40 and 1024 bits
 * Reference: JDK Document http://.../docs/technotes/guides/security/SunProviders.html
 * </pre>
 */
public abstract class DESCoder extends Coder {
	/**
	 * ALGORITHM <br>
	 * 可替换为以下任意�?��算法，同时key值的size相应改变�?
	 * 
	 * <pre>
	 * DES          		key size must be equal to 56
	 * DESede(TripleDES) 	key size must be equal to 112 or 168
	 * AES          		key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
	 * Blowfish     		key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
	 * RC2          		key size must be between 40 and 1024 bits
	 * RC4(ARCFOUR) 		key size must be between 40 and 1024 bits
	 * </pre>
	 * 
	 * 在Key toKey(byte[] key)方法中使用下述代�?
	 * <code>SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);</code> 替换
	 * <code>
	 * DESKeySpec dks = new DESKeySpec(key);
	 * SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
	 * SecretKey secretKey = keyFactory.generateSecret(dks);
	 * </code>
	 */
	public static final String ALGORITHM = "DES";

	/**
	 * 
	 * @Title: toKey
	 * @Description:Transfer Keys
	 * @param @param key
	 * @param @return
	 * @param @throws Exception
	 * @return Key
	 * @throws
	 */
	private static Key toKey(byte[] key) throws Exception {
		DESKeySpec dks = new DESKeySpec(key);
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
		SecretKey secretKey = keyFactory.generateSecret(dks);

		// When other Symmetric encryption algorithm is used,e.g.AES、Blowfish.
		// The following codes can be used to replace the 3 line codes above.
		// SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);

		return secretKey;
	}

	/**
	 * 
	 * @Title: decrypt
	 * @Description: Decrypt
	 * @param @param data
	 * @param @param key
	 * @param @return
	 * @param @throws Exception
	 * @return byte[]
	 * @throws
	 */
	public static byte[] decrypt(byte[] data, String key) throws Exception {
		Key k = toKey(decryptBASE64(key));
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		cipher.init(Cipher.DECRYPT_MODE, k);

		return cipher.doFinal(data);
	}

	/**
	 * 
	 * @Title: encrypt
	 * @Description: Encrypt
	 * @param @param data
	 * @param @param key
	 * @param @return
	 * @param @throws Exception
	 * @return byte[]
	 * @throws
	 */
	public static byte[] encrypt(byte[] data, String key) throws Exception {
		Key k = toKey(decryptBASE64(key));
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		cipher.init(Cipher.ENCRYPT_MODE, k);

		return cipher.doFinal(data);
	}

	/**
	 * 
	 * @Title: initKey
	 * @Description: Generating a key
	 * @param @return
	 * @param @throws Exception
	 * @return String
	 * @throws
	 */
	public static String initKey() throws Exception {
		return initKey(null);
	}

	/**
	 * 
	 * @Title: initKey
	 * @Description: Generating a key
	 * @param @param seed
	 * @param @return
	 * @param @throws Exception
	 * @return String
	 * @throws
	 */
	public static String initKey(String seed) throws Exception {
		SecureRandom secureRandom = null;

		if (seed != null) {
			secureRandom = new SecureRandom(decryptBASE64(seed));
		} else {
			secureRandom = new SecureRandom();
		}

		KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM);
		kg.init(secureRandom);

		SecretKey secretKey = kg.generateKey();

		return encryptBASE64(secretKey.getEncoded());
	}
}